package com.aiwu.widget;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Region;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.customview.widget.ViewDragHelper;

import com.aiwu.library.ui.widget.transformerstip.TransformersTip;
import com.aiwu.library.ui.widget.transformerstip.gravity.TipGravity;
import com.aiwu.library.util.DialogUtil;
import com.aiwu.library.util.DisplayUtil;

import org.citra.citra_emu.R;

/**
 * 主副屏幕 ViewGroup
 */
public class ScreenViewGroup extends FrameLayout implements View.OnClickListener {
    public static final int TOP_SCREEN_WIDTH = 400;     ///< 3DS 主屏 width
    public static final int TOP_SCREEN_HEIGHT = 240;    ///< 3DS 主屏 height
    public static final float TOP_SCREEN_RATIO = TOP_SCREEN_WIDTH * 1f / TOP_SCREEN_HEIGHT;
    public static final int BOTTOM_SCREEN_WIDTH = 320;  ///< 3DS 副屏 width
    public static final int BOTTOM_SCREEN_HEIGHT = 240; ///< 3DS 副屏 height
    public static final float BOTTOM_SCREEN_RATIO = BOTTOM_SCREEN_WIDTH * 1f / BOTTOM_SCREEN_HEIGHT;
    private static final float LANDSCAPE_RATIO = 2.25f;//横屏的主屏:副屏
    //主屏
    private ScreenView mTopScreenView;
    //副屏
    private ScreenView mBottomScreenView;
    //主屏固定比例
    private boolean mTopScreenFixedRatio = false;
    //副屏固定比例
    private boolean mBottomScreenFixedRatio = true;
    //主屏锁定尺寸
    private boolean mTopScreenFixedSize = false;
    //副屏锁定尺寸
    private boolean mBottomScreenFixedSize = false;

    private float translationY = 0f;
    private ObjectAnimator openAnimator, closeAnimator;

    private View smallTitleLayout;
    private View bigTitleLayout;
    private ViewGroup titleBarLayout;
    private Region titleBarRegion = new Region();
    //点击变小的区域
    private Region beSmallRegion = new Region();
    //点击变大的区域
    private Region beBigRegion = new Region();

    private ViewDragHelper mDragHelper;
    private OnActionListener mOnActionListener;

    public ScreenViewGroup(@NonNull Context context) {
        super(context);
        init();
    }

    public ScreenViewGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ScreenViewGroup(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        setBackgroundColor(Color.TRANSPARENT);
        mDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
            //返回true则表示可以捕获该view
            @Override
            public boolean tryCaptureView(@NonNull View view, int pointerId) {
                if (view instanceof ScreenView) {
                    return ((ScreenView) view).getDragDirection() == ScreenView.DIRECTION_CENTER;
                }
                return false;
            }

            //对child移动的边界进行控制
            @Override
            public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {
                //主屏只能在屏幕内
                if (child instanceof ScreenView && ((ScreenView) child).getType() == ScreenView.TOP) {
                    //取得左边界的坐标
                    final int leftBound = getPaddingLeft();
                    //取得右边界的坐标
                    final int rightBound = getWidth() - child.getWidth() - leftBound;
                    //这个地方的含义就是 如果left的值 在leftBound和rightBound之间 那么就返回left
                    //如果left的值 比leftBound还要小 那么就说明 超过了左边界 那我们只能返回给他左边界的值
                    //如果left的值 比rightBound还要大 那么就说明 超过了右边界，那我们只能返回给他右边界的值
                    return Math.min(Math.max(left, leftBound), rightBound);
                }
                //副屏幕可以去屏幕外的右边
                final int leftBound = getPaddingLeft();
                return Math.max(left, leftBound);
            }

            @Override
            public int clampViewPositionVertical(@NonNull View child, int top, int dy) {
                if (child instanceof ScreenView && ((ScreenView) child).getType() == ScreenView.TOP) {
                    final int topBound = getPaddingTop();
                    final int bottomBound = getHeight() - child.getHeight() - topBound;
                    return Math.min(Math.max(top, topBound), bottomBound);
                }
                final int topBound = getPaddingTop();
                return Math.max(top, topBound);
            }

            @Override
            public void onViewCaptured(@NonNull View capturedChild, int activePointerId) {

            }

            @Override
            public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {
                FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) releasedChild.getLayoutParams();
                lp.setMargins(releasedChild.getLeft(), releasedChild.getTop(), 0, 0);
                releasedChild.setLayoutParams(lp);
            }

            @Override
            public int getViewVerticalDragRange(@NonNull View child) {
                return getMeasuredHeight() - child.getMeasuredHeight();
            }

            @Override
            public int getViewHorizontalDragRange(@NonNull View child) {
                return getMeasuredWidth() - child.getMeasuredWidth();
            }
        });
        addTitleBarLayout();
    }

    /**
     * 添加头部
     */
    private void addTitleBarLayout() {
        titleBarLayout = (ViewGroup) View.inflate(getContext(), R.layout.titlebar_screen, null);
        addView(titleBarLayout, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        smallTitleLayout = findViewById(R.id.smallTitle);
        bigTitleLayout = findViewById(R.id.bigTitle);
        openTitleLayout(false);
        bindTitleView();
    }

    private void bindTitleView() {
        findViewById(R.id.btn_back).setOnClickListener(this);
        findViewById(R.id.btn_revert).setOnClickListener(this);
        findViewById(R.id.btn_reset).setOnClickListener(this);
        findViewById(R.id.btn_fixed_ratio).setOnClickListener(this);
        findViewById(R.id.btn_fixed_size).setOnClickListener(this);
    }

    /**
     * 添加默认的主副屏幕
     */
    public void addDefaultScreenView() {
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        boolean isLandscape = width > height;
        int topScreenWidth;
        if (isLandscape) {
            float emulationAspectRatio = TOP_SCREEN_HEIGHT * LANDSCAPE_RATIO / (TOP_SCREEN_WIDTH * LANDSCAPE_RATIO + BOTTOM_SCREEN_WIDTH);
            int w = (int) Math.min(width, height / emulationAspectRatio);
            int h = (int) (w * emulationAspectRatio);
            float largeScreenAspectRatio = TOP_SCREEN_HEIGHT * 1.0f / TOP_SCREEN_WIDTH;
            topScreenWidth = (int) Math.min(w, h / largeScreenAspectRatio);
        } else {
            topScreenWidth = width;
        }
        final int topScreenHeight = (int) (topScreenWidth / (TOP_SCREEN_WIDTH * 1.0f / TOP_SCREEN_HEIGHT));
        mTopScreenView = new ScreenView(getContext(), this, ScreenView.TOP);
        LayoutParams lpTop = new LayoutParams(topScreenWidth, topScreenHeight);


        final int bottomScreenWidth = isLandscape ? width - topScreenWidth : width;
        final int bottomScreenHeight = (int) (bottomScreenWidth / (BOTTOM_SCREEN_WIDTH * 1.0f / BOTTOM_SCREEN_HEIGHT));
        mBottomScreenView = new ScreenView(getContext(), this, ScreenView.BOTTOM);
        LayoutParams lpBottom = new LayoutParams(bottomScreenWidth, bottomScreenHeight);
        if (isLandscape) {
            lpBottom.setMargins(topScreenWidth, 0, 0, 0);
        } else {
            lpBottom.setMargins(0, topScreenHeight, 0, 0);
        }

        addView(mBottomScreenView, 0, lpBottom);
        addView(mTopScreenView, 0, lpTop);
    }

    /**
     * 添加已有的主副屏幕
     */
    public void addExistingScreenView(int topLeft, int topTop, int topRight, int topBottom, int bottomLeft, int bottomTop, int bottomRight, int bottomBottom) {
        mTopScreenView = new ScreenView(getContext(), this, ScreenView.TOP);

        LayoutParams lpTop = new LayoutParams(topRight - topLeft, topBottom - topTop);
        lpTop.setMargins(topLeft, topTop, 0, 0);
        mTopScreenFixedRatio = (topRight - topLeft) * 1f / (topBottom - topTop) == TOP_SCREEN_RATIO;

        mBottomScreenView = new ScreenView(getContext(), this, ScreenView.BOTTOM);
        LayoutParams lpBottom = new LayoutParams(bottomRight - bottomLeft, bottomBottom - bottomTop);
        lpBottom.setMargins(bottomLeft, bottomTop, 0, 0);
        mBottomScreenFixedRatio = (bottomRight - bottomLeft) * 1f / (bottomBottom - bottomTop) == BOTTOM_SCREEN_RATIO;

        addView(mBottomScreenView, 0, lpBottom);
        addView(mTopScreenView, 0, lpTop);
    }

    /**
     * 复位
     */
    public void resetDefaultScreenView() {
        int width = getMeasuredWidth();
        int height = getMeasuredHeight();
        boolean isLandscape = width > height;
        int topScreenWidth;
        if (isLandscape) {
            float emulationAspectRatio = TOP_SCREEN_HEIGHT * LANDSCAPE_RATIO / (TOP_SCREEN_WIDTH * LANDSCAPE_RATIO + BOTTOM_SCREEN_WIDTH);
            int w = (int) Math.min(width, height / emulationAspectRatio);
            int h = (int) (w * emulationAspectRatio);
            float largeScreenAspectRatio = TOP_SCREEN_HEIGHT * 1.0f / TOP_SCREEN_WIDTH;
            topScreenWidth = (int) Math.min(w, h / largeScreenAspectRatio);
        } else {
            topScreenWidth = width;
        }
        final int topScreenHeight = (int) (topScreenWidth / (TOP_SCREEN_WIDTH * 1.0f / TOP_SCREEN_HEIGHT));
        LayoutParams lpTop = new LayoutParams(topScreenWidth, topScreenHeight);
        mTopScreenView.setLayoutParams(lpTop);

        final int bottomScreenWidth = isLandscape ? width - topScreenWidth : width;
        final int bottomScreenHeight = (int) (bottomScreenWidth / (BOTTOM_SCREEN_WIDTH * 1.0f / BOTTOM_SCREEN_HEIGHT));
        LayoutParams lpBottom = new LayoutParams(bottomScreenWidth, bottomScreenHeight);
        if (isLandscape) {
            lpBottom.setMargins(topScreenWidth, 0, 0, 0);
        } else {
            lpBottom.setMargins(0, topScreenHeight, 0, 0);
        }
        mBottomScreenView.setLayoutParams(lpBottom);
    }

    /**
     * 复位
     */
    public void resetExistingScreenView(int topLeft, int topTop, int topRight, int topBottom, int bottomLeft, int bottomTop, int bottomRight, int bottomBottom) {
        if (mTopScreenView == null || mBottomScreenView == null) {
            return;
        }
        LayoutParams lpTop = new LayoutParams(topRight - topLeft, topBottom - topTop);
        lpTop.setMargins(topLeft, topTop, 0, 0);
        mTopScreenView.setLayoutParams(lpTop);

        LayoutParams lpBottom = new LayoutParams(bottomRight - bottomLeft, bottomBottom - bottomTop);
        lpBottom.setMargins(bottomLeft, bottomTop, 0, 0);
        mBottomScreenView.setLayoutParams(lpBottom);
    }

    /**
     * 结果位置
     *
     * @return {主屏left,主屏top,主屏right,主屏bottom,副屏left,副屏top,副屏right,副屏bottom}
     */
    public int[] getResultLocation() {
        if (mTopScreenView == null || mBottomScreenView == null) {
            return new int[]{};
        }
        return new int[]{mTopScreenView.getLeft(), mTopScreenView.getTop(), mTopScreenView.getRight(), mTopScreenView.getBottom(),
                mBottomScreenView.getLeft(), mBottomScreenView.getTop(), mBottomScreenView.getRight(), mBottomScreenView.getBottom()};
    }

    /**
     * 展开标题栏
     */
    private void openTitleLayout(boolean animation) {
        if (bigTitleLayout.getVisibility() == VISIBLE && bigTitleLayout.getTranslationY() == 0 && smallTitleLayout.getVisibility() == INVISIBLE) {
            return;
        }
        if (animation) {
            if (openAnimator == null) {
                openAnimator = ObjectAnimator.ofFloat(bigTitleLayout, "TranslationY", -translationY, 0);
                openAnimator.addListener(new AnimatorListenerAdapter() {
                    @Override
                    public void onAnimationStart(Animator animation) {
                        super.onAnimationStart(animation);
                        bigTitleLayout.setVisibility(VISIBLE);
                        smallTitleLayout.setVisibility(INVISIBLE);
                    }
                });
            }
            openAnimator.start();
        } else {
            bigTitleLayout.setTranslationY(0);
            bigTitleLayout.setVisibility(VISIBLE);
            smallTitleLayout.setVisibility(INVISIBLE);
        }
    }

    /**
     * 折叠标题栏
     */
    private void closeTitleLayout() {
        if (smallTitleLayout.getVisibility() == VISIBLE && bigTitleLayout.getVisibility() == INVISIBLE) {
            return;
        }
        if (closeAnimator == null) {
            closeAnimator = ObjectAnimator.ofFloat(bigTitleLayout, "TranslationY", 0, -translationY);
            closeAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    smallTitleLayout.setVisibility(VISIBLE);
                    bigTitleLayout.setVisibility(INVISIBLE);
                }
            });
        }
        closeAnimator.start();
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (getChildCount() >= 3) {
            throw new IllegalArgumentException("最多只能有3个child");
        }
        super.addView(child, index, params);
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        int dp20 = DisplayUtil.dp2px(20);
        int width = right - left;
        titleBarRegion.set(0, 0, width, bigTitleLayout.getMeasuredHeight() - dp20);
        int l = width / 2 - dp20 * 2;
        int r = width / 2 + dp20 * 2;
        beSmallRegion.set(l, bigTitleLayout.getMeasuredHeight() - dp20, r, bigTitleLayout.getMeasuredHeight());
        beBigRegion.set(l, 0, r, dp20);
        translationY = bigTitleLayout.getMeasuredHeight() - smallTitleLayout.getMeasuredHeight();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (beBigRegion.contains((int) event.getX(), (int) event.getY())) {
            return true;
        } else if (beSmallRegion.contains((int) event.getX(), (int) event.getY())) {
            return true;
        }
        return mDragHelper.shouldInterceptTouchEvent(event);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            if (beBigRegion.contains((int) event.getX(), (int) event.getY())) {
                openTitleLayout(true);
                return true;
            } else if (beSmallRegion.contains((int) event.getX(), (int) event.getY())) {
                closeTitleLayout();
                return true;
            }
        }
        mDragHelper.processTouchEvent(event);
        return true;
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_back:
                if (mOnActionListener != null) {
                    mOnActionListener.showSaveConfigTip();
                }
                break;
            case R.id.btn_revert:
                showRevertPop();
                break;
            case R.id.btn_reset:
                showResetPop();
                break;
            case R.id.btn_fixed_ratio:
                showFixedRatioPop(v);
                break;
            case R.id.btn_fixed_size:
                showFixedSizePop(v);
                break;
        }
    }

    /**
     * 固定比例的弹窗
     *
     * @param anchorView
     */
    private void showFixedRatioPop(View anchorView) {
        new TransformersTip(anchorView, R.layout.pop_fixed_ratio) {
            @Override
            protected void initView(View contentView) {
                CheckBox cbTopScreen = contentView.findViewById(R.id.cb_top_screen);
                CheckBox cbBottomScreen = contentView.findViewById(R.id.cb_bottom_screen);
                cbTopScreen.setChecked(mTopScreenFixedRatio);
                cbBottomScreen.setChecked(mBottomScreenFixedRatio);
                cbTopScreen.setOnCheckedChangeListener((buttonView, isChecked) -> {
                    if (buttonView.isPressed())
                        mTopScreenFixedRatio = isChecked;
                });
                cbBottomScreen.setOnCheckedChangeListener((buttonView, isChecked) -> {
                    if (buttonView.isPressed())
                        mBottomScreenFixedRatio = isChecked;
                });
            }
        }
                .setTipGravity(TipGravity.TO_BOTTOM_CENTER)
                .setBackgroundDimEnabled(false)
                .setDismissOnTouchOutside(true)
                .setTipOffsetYDp(5)
                .show();
    }

    /**
     * 固定大小的弹窗
     *
     * @param anchorView
     */
    private void showFixedSizePop(View anchorView) {
        new TransformersTip(anchorView, R.layout.pop_fixed_ratio) {
            @Override
            protected void initView(View contentView) {
                CheckBox cbTopScreen = contentView.findViewById(R.id.cb_top_screen);
                CheckBox cbBottomScreen = contentView.findViewById(R.id.cb_bottom_screen);
                cbTopScreen.setChecked(mTopScreenFixedSize);
                cbBottomScreen.setChecked(mBottomScreenFixedSize);
                cbTopScreen.setOnCheckedChangeListener((buttonView, isChecked) -> {
                    if (buttonView.isPressed())
                        mTopScreenFixedSize = isChecked;
                });
                cbBottomScreen.setOnCheckedChangeListener((buttonView, isChecked) -> {
                    if (buttonView.isPressed())
                        mBottomScreenFixedSize = isChecked;
                });
            }
        }
                .setTipGravity(TipGravity.TO_BOTTOM_CENTER)
                .setBackgroundDimEnabled(false)
                .setDismissOnTouchOutside(true)
                .setTipOffsetYDp(5)
                .show();
    }

    /**
     * 是否恢复按键弹窗
     */
    private void showRevertPop() {
        DialogUtil.showTip(getContext(), R.string.reset_tip, v -> {
            if (mOnActionListener != null) {
                mOnActionListener.resetScreenView();
            }
        }, null);
    }

    private void showResetPop() {
        DialogUtil.showTip(getContext(), "是否恢复到初始的配置？", v -> {
            resetDefaultScreenView();
        }, null);
    }

    public boolean isTopScreenFixedRatio() {
        return mTopScreenFixedRatio;
    }

    public boolean isBottomScreenFixedRatio() {
        return mBottomScreenFixedRatio;
    }

    public boolean isTopScreenFixedSize() {
        return mTopScreenFixedSize;
    }

    public boolean isBottomScreenFixedSize() {
        return mBottomScreenFixedSize;
    }

    public void setOnActionListener(OnActionListener onActionListener) {
        this.mOnActionListener = onActionListener;
    }

    public interface OnActionListener {
        void showSaveConfigTip();

        void resetScreenView();
    }
}
